home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 85 / CD Temático 40 Febrero 2004.iso / DOS / ntfs / common / util.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-02-11  |  8.3 KB  |  368 lines

  1. /*
  2.  *  util.c
  3.  *  Miscellaneous support
  4.  *
  5.  *  Copyright (C) 1997,1999 Martin von L÷wis
  6.  *  Copyright (C) 1997 RΘgis Duchesne
  7.  *
  8.  *  The utf8 routines are copied from Python wstrop module.
  9.  */
  10.  
  11. #include "ntfstypes.h"
  12. #include "struct.h"
  13. #include "util.h"
  14.  
  15. #include <errno.h>
  16. /* FreeBSD doesn't seem to have EILSEQ in errno.h */
  17. #ifndef EILSEQ
  18. # define EILSEQ EINVAL
  19. #endif
  20. #include "support.h"
  21.  
  22. /* Converts a single wide character to a sequence of utf8 bytes.
  23.  * The character is represented in host byte order.
  24.  * Returns the number of bytes, or 0 on error.
  25.  */
  26. static int
  27. to_utf8(ntfs_u16 c,unsigned char* buf)
  28. {
  29.     if(c==0)
  30.         return 0; /* No support for embedded 0 runes */
  31.     if(c<0x80){
  32.         if(buf)buf[0]=(unsigned char)c;
  33.         return 1;
  34.     }
  35.     if(c<0x800){
  36.         if(buf){
  37.             buf[0] = 0xc0 | (c>>6);
  38.             buf[1] = 0x80 | (c & 0x3f);
  39.         }
  40.         return 2;
  41.     }
  42.     if(c<0x10000){
  43.         if(buf){
  44.             buf[0] = 0xe0 | (c>>12);
  45.             buf[1] = 0x80 | ((c>>6) & 0x3f);
  46.             buf[2] = 0x80 | (c & 0x3f);
  47.         }
  48.         return 3;
  49.     }
  50.     /* We don't support characters above 0xFFFF in NTFS */
  51.     return 0;
  52. }
  53.  
  54. /* Decodes a sequence of utf8 bytes into a single wide character.
  55.  * The character is returned in host byte order.
  56.  * Returns the number of bytes consumed, or 0 on error.
  57.  */
  58. static int
  59. from_utf8(const unsigned char* str,ntfs_u16 *c)
  60. {
  61.     int l=0,i;
  62.  
  63.     if(*str<0x80){
  64.         *c = *str;
  65.         return 1;
  66.     }
  67.     if(*str<0xc0) /* lead byte must not be 10xxxxxx */
  68.         return 0;   /* is c0 a possible lead byte? */
  69.     if(*str<0xe0){         /* 110xxxxx */
  70.         *c = *str & 0x1f;
  71.         l=2;
  72.     }else if(*str<0xf0){   /* 1110xxxx */
  73.         *c = *str & 0xf;
  74.         l=3;
  75.     }else if(*str<0xf8){   /* 11110xxx */
  76.         *c = *str & 7;
  77.         l=4;
  78.     }else /* We don't support characters above 0xFFFF in NTFS */
  79.         return 0;
  80.      
  81.  
  82.     for(i=1;i<l;i++){
  83.         /* all other bytes must be 10xxxxxx */
  84.         if((str[i] & 0xc0) != 0x80)
  85.             return 0;
  86.         *c <<= 6;
  87.         *c |= str[i] & 0x3f;
  88.     }
  89.     return l;
  90. }
  91.  
  92. /* Converts wide string to UTF-8. Expects two in- and two out-parameters.
  93.  * Returns 0 on success, or error code. 
  94.  * The caller has to free the result string.
  95.  * There is no support for UTF-16, yet
  96.  */
  97. static int ntfs_dupuni2utf8(ntfs_u16* in, int in_len,char **out,int *out_len)
  98. {
  99.     int i,tmp;
  100.     int len8;
  101.     unsigned char *result;
  102.  
  103.     ntfs_debug(DEBUG_NAME1,"converting l=%d\n",in_len);
  104.     /* count the length of the resulting UTF-8 */
  105.     for(i=len8=0;i<in_len;i++){
  106.         tmp=to_utf8(NTFS_GETU16(in+i),0);
  107.         if(!tmp)
  108.             /* invalid character */
  109.             return EILSEQ;
  110.         len8+=tmp;
  111.     }
  112.     *out=result=ntfs_malloc(len8+1); /* allow for zero-termination */
  113.  
  114.     if(!result)
  115.         return ENOMEM;
  116.     result[len8]='\0';
  117.     *out_len=len8;
  118.     for(i=len8=0;i<in_len;i++)
  119.         len8+=to_utf8(NTFS_GETU16(in+i),result+len8);
  120.     ntfs_debug(DEBUG_NAME1,"result %p:%s\n",result,result);
  121.     return 0;
  122. }
  123.  
  124. /* Converts an UTF-8 sequence to a wide string. Same conventions as the
  125.  * previous function
  126.  */
  127. static int ntfs_duputf82uni(unsigned char* in, int in_len,ntfs_u16** out,int *out_len)
  128. {
  129.     int i,tmp;
  130.     int len16;
  131.  
  132.     ntfs_u16* result;
  133.     ntfs_u16 wtmp;
  134.     for(i=len16=0;i<in_len;i+=tmp,len16++){
  135.         tmp=from_utf8(in+i,&wtmp);
  136.         if(!tmp)
  137.             return EILSEQ;
  138.     }
  139.     *out=result=ntfs_malloc(2*(len16+1));
  140.     if(!result)
  141.         return ENOMEM;
  142.     result[len16]=0;
  143.     *out_len=len16;
  144.     for(i=len16=0;i<in_len;i+=tmp,len16++)
  145.     {
  146.         tmp=from_utf8(in+i, &wtmp);
  147.         NTFS_PUTU16(result+len16, wtmp);
  148.     }
  149.     return 0;
  150. }
  151.  
  152. /* See above. Produces ISO-8859-1 from wide strings */
  153. static int ntfs_dupuni288591(ntfs_u16* in,int in_len,char** out,int *out_len)
  154. {
  155.     int i;
  156.     char *result;
  157.  
  158.     /* check for characters out of range */
  159.     for(i=0;i<in_len;i++)
  160.         if(NTFS_GETU16(in+i)>=256)
  161.             return EILSEQ;
  162.     *out=result=ntfs_malloc(in_len+1);
  163.     if(!result)
  164.         return ENOMEM;
  165.     result[in_len]='\0';
  166.     *out_len=in_len;
  167.     for(i=0;i<in_len;i++)
  168.         result[i]=(unsigned char)NTFS_GETU16(in+i);
  169.     return 0;
  170. }
  171.  
  172. /* See above */
  173. static int ntfs_dup885912uni(unsigned char* in,int in_len,ntfs_u16 **out,int *out_len)
  174. {
  175.     int i;
  176.  
  177.     ntfs_u16* result;
  178.     *out=result=ntfs_malloc(2*in_len);
  179.     if(!result)
  180.         return ENOMEM;
  181.     *out_len=in_len;
  182.     for(i=0;i<in_len;i++)
  183.         NTFS_PUTU16(result+i,in[i]);
  184.     return 0;
  185. }
  186.  
  187. /* Encodings dispatcher */
  188. int ntfs_encodeuni(ntfs_volume *vol,ntfs_u16 *in, int in_len,
  189.            char **out, int *out_len)
  190. {
  191.     if(vol->nct & nct_utf8)
  192.         return ntfs_dupuni2utf8(in,in_len,out,out_len);
  193.     else if(vol->nct & nct_iso8859_1)
  194.         return ntfs_dupuni288591(in,in_len,out,out_len);
  195.     else if(vol->nct & (nct_map|nct_uni_xlate))
  196.         /* uni_xlate is handled inside map */
  197.         return ntfs_dupuni2map(vol,in,in_len,out,out_len);
  198.     else
  199.         return EINVAL; /* unknown encoding */
  200. }
  201.  
  202. int ntfs_decodeuni(ntfs_volume *vol,char *in, int in_len,
  203.            ntfs_u16 **out, int *out_len)
  204. {
  205.     if(vol->nct & nct_utf8)
  206.         return ntfs_duputf82uni(in,in_len,out,out_len);
  207.     else if(vol->nct & nct_iso8859_1)
  208.         return ntfs_dup885912uni(in,in_len,out,out_len);
  209.     else if(vol->nct & (nct_map | nct_uni_xlate))
  210.         return ntfs_dupmap2uni(vol,in,in_len,out,out_len);
  211.     else
  212.         return EINVAL;
  213. }
  214.  
  215. /* Same address space copies */
  216. void ntfs_put(ntfs_io *dest,void *src,ntfs_size_t n)
  217. {
  218.     ntfs_memcpy(dest->param,src,n);
  219.     ((char*)dest->param)+=n;
  220. }
  221.  
  222. void ntfs_get(void* dest,ntfs_io *src,ntfs_size_t n)
  223. {
  224.     ntfs_memcpy(dest,src->param,n);
  225.     ((char*)src->param)+=n;
  226. }
  227.  
  228. void *ntfs_calloc(int size)
  229. {
  230.     void *result=ntfs_malloc(size);
  231.     if(result)
  232.         ntfs_bzero(result,size);
  233.     return result;
  234. }
  235.  
  236. #if 0
  237. /* copy len unicode characters from from to to :) */
  238. void ntfs_uni2ascii(char *to,char *from,int len)
  239. {
  240.     int i;
  241.  
  242.     for(i=0;i<len;i++)
  243.         to[i]=from[2*i];
  244.     to[i]='\0';
  245. }
  246. #endif
  247.  
  248. /* copy len asci characters from from to to :) */
  249. void ntfs_ascii2uni(short int *to,char *from,int len)
  250. {
  251.     int i;
  252.  
  253.     for(i=0;i<len;i++)
  254.         to[i]=from[i];
  255.     to[i]=0;
  256. }
  257.  
  258. /* strncmp for Unicode strings */
  259. int ntfs_uni_strncmp(short int* a,short int *b,int n)
  260. {
  261.     int i;
  262.  
  263.     for(i=0;i<n;i++)
  264.     {
  265.         if(a[i]<b[i])
  266.             return -1;
  267.         if(b[i]<a[i])
  268.             return 1;
  269.     }
  270.     return 0;
  271. }
  272.  
  273. /* strncmp between Unicode and ASCII strings */
  274. int ntfs_ua_strncmp(short int* a,char* b,int n)
  275. {
  276.     int i;
  277.  
  278.     for(i=0;i<n;i++)
  279.     {
  280.         if(NTFS_GETU16(a+i)<b[i])
  281.             return -1;
  282.         if(b[i]<NTFS_GETU16(a+i))
  283.             return 1;
  284.     }
  285.     return 0;
  286. }
  287.  
  288. /* Convert the NT UTC (based 1.1.1601, in hundred nanosecond units)
  289.  * into Unix UTC (based 1.1.1970, in seconds)
  290.  */
  291. ntfs_time_t ntfs_ntutc2unixutc(ntfs_time64_t ntutc)
  292. {
  293. /*
  294.  * This is very gross because
  295.  * 1: We must do 64-bit division on a 32-bit machine
  296.  * 2: We can't use libgcc for long long operations in the kernel
  297.  * 3: Floating point math in the kernel would corrupt user data
  298.  */
  299.     const unsigned int D = 10000000;
  300.     unsigned int H = (unsigned int)(ntutc >> 32);
  301.     unsigned int L = (unsigned int)ntutc;
  302.     unsigned int numerator2;
  303.     unsigned int lowseconds;
  304.     unsigned int result;
  305.  
  306.     /* It is best to subtract 0x019db1ded53e8000 first. */
  307.     /* Then the 1601-based date becomes a 1970-based date. */
  308.     if(L < (unsigned)0xd53e8000) H--;
  309.     L -= (unsigned)0xd53e8000;
  310.     H -= (unsigned)0x019db1de;
  311.  
  312.     /*
  313.      * Now divide 64-bit numbers on a 32-bit machine :-)
  314.      * With the subtraction already done, the result fits in 32 bits.
  315.      * The numerator fits in 56 bits and the denominator fits
  316.      * in 24 bits, so we can shift by 8 bits to make this work.
  317.      */
  318.  
  319.     numerator2  = (H<<8) | (L>>24);
  320.     result      = (numerator2 / D);   /* shifted 24 right!! */
  321.     lowseconds  = result << 24;
  322.  
  323.     numerator2  = ((numerator2-result*D)<<8) | ((L>>16)&0xff);
  324.     result      = (numerator2 / D);   /* shifted 16 right!! */
  325.     lowseconds |= result << 16;
  326.  
  327.     numerator2  = ((numerator2-result*D)<<8) | ((L>>8)&0xff);
  328.     result      = (numerator2 / D);   /* shifted 8 right!! */
  329.     lowseconds |= result << 8;
  330.  
  331.     numerator2  = ((numerator2-result*D)<<8) | (L&0xff);
  332.     result      = (numerator2 / D);   /* not shifted */
  333.     lowseconds |= result;
  334.  
  335.     return lowseconds;
  336. }
  337.  
  338. /* Convert the Unix UTC into NT UTC */
  339. ntfs_time64_t ntfs_unixutc2ntutc(ntfs_time_t t)
  340. {
  341.     return ((t + (ntfs_time64_t)(369*365+89)*24*3600) * 10000000);
  342. }
  343.  
  344. /* Fill index name. */
  345.  
  346. void
  347. ntfs_indexname(char *buf, int type)
  348. {
  349.     char hex[]="0123456789ABCDEF";
  350.     int index;
  351.     *buf++='$';
  352.     *buf++='I';
  353.     for (index=24; index>0; index-=4)
  354.         if((0xF << index) & type)
  355.             break;
  356.     while(index>=0) {
  357.         *buf++ = hex[(type >> index) & 0xF];
  358.         index-=4;
  359.     }
  360.     *buf='\0';
  361. }
  362.  
  363. /*
  364.  * Local variables:
  365.  * c-file-style: "linux"
  366.  * End:
  367.  */
  368.